package cn.demoxy.service.impl;

import cn.demoxy.enums.ExceptionMessageEnum;
import cn.demoxy.exception.DemoException;
import cn.demoxy.mapper.DemoTableMapper;
import cn.demoxy.model.dto.DemoTableDTO;
import cn.demoxy.model.entity.DemoTable;
import cn.demoxy.service.IDemoTableService;
import cn.demoxy.utils.FileUtils;
import cn.demoxy.utils.ZipUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.UnsupportedEncodingException;
import java.sql.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.demoxy.constant.CommonConstant.DRIVER_NAME;

/**
 * @auther demo
 * @date 2022/6/2 11:42
 * 数据源表业务实现类
 */
@Service
@AllArgsConstructor
public class DemoTableServiceImpl extends ServiceImpl<DemoTableMapper, DemoTable> implements IDemoTableService {

    private HttpServletResponse response;
    /**
     * 从jdbcUrl中取出数据库名
     * @param s
     * @return
     */
    public String subUrl(String s){
        if (s.contains("?")) {
            int i = StringUtils.ordinalIndexOf(s, "/", 3);
            int i1 = StringUtils.ordinalIndexOf(s, "?", 1);
            String substring = s.substring(i+1, i1);
            return substring;
        }else {
            int i = StringUtils.ordinalIndexOf(s, "/", 3);
            String substring = s.substring(i+1);
            return substring;
        }
    }

    @Override
    public IPage<DemoTable> selectAllTablesByDataBase(DemoTableDTO tableDTO) throws SQLException {
        List<DemoTable> demoTables = new ArrayList<>();
        List<DemoTable> size = new ArrayList<>();
        Connection connection = null;
        ResultSet resultSet = null;
        PreparedStatement statement = null;
        String sql ;
        String total;
        try {

            // 获取连接
            connection = DriverManager.getConnection(tableDTO.getUrl(), tableDTO.getUsername(), tableDTO.getPassword());
            String data = subUrl(tableDTO.getUrl());
            if (tableDTO.getTableName()!=null){
                sql = "select table_name,engine,create_time,table_comment from information_schema.tables where table_schema='" + data + "' and table_name " +
                        " like '%"+tableDTO.getTableName()+"%' "+"limit "+tableDTO.getCurrent()+","+tableDTO.getSize();
                total="select table_name,engine,create_time,table_comment from information_schema.tables where table_schema='" + data + "' and table_name " +
                        " like '%"+tableDTO.getTableName()+"%' ";
            }else {
                sql = "select table_name,engine,create_time,table_comment from information_schema.tables where table_schema='" + data + "' "+"limit "+tableDTO.getCurrent()+","+tableDTO.getSize();
                total="select table_name,engine,create_time,table_comment from information_schema.tables where table_schema=' " + data + "'";
            }
            statement = connection.prepareStatement(total);
            ResultSet totals = statement.executeQuery();
            while (totals.next()) {
                DemoTable demoTable1 = new DemoTable();
                size.add(demoTable1);
            }

                //得到statement对象
                statement = connection.prepareStatement(sql);
                resultSet = statement.executeQuery();
                while (resultSet.next()) {
                    String table_name = resultSet.getString("table_name");
                    String engine = resultSet.getString("engine");
                    String create_time = resultSet.getString("create_time");
                    String table_comment = resultSet.getString("table_comment");
                    DemoTable demoTable = new DemoTable();
                    demoTable.setTableName(table_name);
                    demoTable.setStorageEngine(engine);
                    demoTable.setTableDesc(table_comment);
                    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    //日期类型转换
                    LocalDateTime parse = LocalDateTime.parse(create_time, dateTimeFormatter);
                    demoTable.setCreateTime(parse);
                    demoTables.add(demoTable);
                }


        } catch (Exception e) {
            e.printStackTrace();
            throw new DemoException(ExceptionMessageEnum.DATASOURCE_CONNECTION_TIME_OUT.getCode(),ExceptionMessageEnum.DATASOURCE_CONNECTION_TIME_OUT.getMsg());
        }

        Page<DemoTable> page = new Page<>();
        page.setRecords(demoTables);
        page.setTotal(size.size());
        page.setSize(tableDTO.getSize());
        return page;
    }

    @Override
    public void codeGenerator(DemoTableDTO tableDTO) throws FileNotFoundException, UnsupportedEncodingException {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setBaseResultMap(true);
        final String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor(tableDTO.getAuth());
        gc.setOpen(false);
        // 实体属性 Swagger2 注解
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl(tableDTO.getUrl());
        // dsc.setSchemaName("public");
        dsc.setDriverName(DRIVER_NAME);
        dsc.setUsername(tableDTO.getUsername());
        dsc.setPassword(tableDTO.getPassword());
        mpg.setDataSource(dsc);

        // 包配置
        final PackageConfig pc = new PackageConfig();
        pc.setParent("");
        mpg.setPackageInfo(pc);
        pc.setModuleName(tableDTO.getModule());
        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
                Map<String, Object> map = new HashMap<String, Object>(2);
//                map.put("apiPath", "${demo.api-path}");
                map.put("hasPermission", false);
				/*map.put("replaceEntityName", "Sys");
				map.put("empty", "");*/
                this.setMap(map);
            }
        };

        // 如果模板引擎是 freemarker
        String apiTemplatePath = "/templates/demo.controller.java.ftl";
        String mapperXMLTemplatePath = "/templates/demo.mapper.xml.ftl";
        String queryTemplatePath = "/templates/demo.model.dto.java.ftl";
        String voTemplatePath = "/templates/demo.model.vo.java.ftl";
        String serviceTemplatePath = "/templates/demo.service.java.ftl";
        String serviceImplTemplatePath = "/templates/demo.serviceImpl.java.ftl";
        String mapperTemplatePath = "/templates/demo.mapper.java.ftl";
        String entityTemplatePath = "/templates/demo.entity.java.ftl";
        String dirUrl = tableDTO.getModule().replace(".", "/");
        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<FileOutConfig>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(apiTemplatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+dirUrl+"/controller/" + tableInfo.getEntityName() + "Controller" + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig(mapperXMLTemplatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
//                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
//                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
                return projectPath + "/src/main/resources/" + dirUrl + "/mapper/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        focList.add(new FileOutConfig(queryTemplatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+dirUrl+"/model/dto/" + tableInfo.getEntityName() + "DTO" + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig(voTemplatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+dirUrl+"/model/vo/" + tableInfo.getEntityName() + "VO" + StringPool.DOT_JAVA;
            }
        });

        focList.add(new FileOutConfig(entityTemplatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+dirUrl+"/model/entity/" + tableInfo.getEntityName()  + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig(serviceTemplatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+dirUrl+"/service/" + tableInfo.getServiceName()  + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig(serviceImplTemplatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+dirUrl+"/service/impl/" + tableInfo.getServiceImplName()  + StringPool.DOT_JAVA;
            }
        });
        focList.add(new FileOutConfig(mapperTemplatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return projectPath + "/src/main/java/"+dirUrl+"/mapper/" + tableInfo.getMapperName()  + StringPool.DOT_JAVA;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setController(null);
        templateConfig.setXml(null);
        templateConfig.setEntity(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        // 公共父类
        strategy.setSuperEntityClass("cn.demoxy.base.BaseEntity");
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns("id", "is_deleted", "create_time", "create_by", "update_time", "update_by");
        strategy.setInclude(tableDTO.getTables().split(","));
        strategy.setControllerMappingHyphenStyle(true);
        // strategy.setTablePrefix(pc.getModuleName() + "t_");
        // strategy.setTablePrefix("t_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
        //创建文件流
        File file = new File(projectPath + "\\DemoCode" + ".zip");
        FileOutputStream fos1 = new FileOutputStream(file);
        //将生成文件压缩成zip
        ZipUtils.toZip(projectPath + "/src", fos1, true);
        //返回前端下载
        FileUtils.downLoadZip(projectPath + "\\DemoCode.zip", response);
        //删除生成的代码
        FileUtils.delDir(projectPath + "/src");
        //删除压缩包
        file.delete();
    }
}
